Debugging

This is a simple tutorial using the top-level processing Qt events:
  $ eql5 -qtpl

Example 1: Error on REPL (trivial)


  EQL-USER[1]> (/ 0)

  Condition of type: DIVISION-BY-ZERO

  Available restarts:

  1. (RESTART-TOPLEVEL) Go back to Top-Level REPL.
  2. (RESTART-QT-EVENTS) Restart Qt event processing.

  ** BREAK [LEVEL 2]>
    
   debug  dialog

Note that all debug input is handled in a debug dialog, not in the console window.

So, either type the restart number in the dialog

  :r1
or just click Cancel / hit Escape, which will always choose :r1.

Type :h for all available debug options.

Both restarts will have the same effect here, see note at bottom.


 

Example 2: Error during Qt event processing

Start calculator example:
  $ eql5 -qtpl examples/X-extras/calculator

Let's run this function:
  EQL-USER[1]> (clc:auto "42 ? blah")

This will output 2 errors, without breaking into the debugger:

  [EQL:err] QFIND-CHILD #<QDialog "" 0x39737d0 [1]> "?"

  [EQL:err] QINVOKE-METHOD NIL NIL "animateClick" (400)
    

Note: After eventual print output (like the above), you won't see a fresh top-level prompt.
Don't get confused by this, as you can continue to enter commands.


Now make EQL errors break into the debugger:
  EQL-USER[2]> (setf eql:*break-on-errors* t)

Run our function again:

  EQL-USER[3]> (clc:auto "42 ? blah")

  Condition of type: SIMPLE-CONDITION

  [EQL:err] QFIND-CHILD #<QDialog "" 0x39737d0 [1]> "?"

  Available restarts:

  1. (CONTINUE) Return from BREAK.
  2. (RESTART-QT-EVENTS) Restart Qt event processing.

  ** BREAK [LEVEL 1]>
    
   debug dialog

Now there are 2 possible restarts:

  :r1
(CONTINUE) will continue execution, which will break on the next error, then finish our function.
  :r2
(RESTART-QT-EVENTS) will abort execution, returning to the REPL immediately.




Notes

There is one situation where interactive debugging won't work, and this is in code inside an (overridden)
  "paintEvent(QPaintEvent*)"
function, as this may cause recursive paint events and segfaults.
 
 
To exit instantly from EQL during debugging (on nasty errors), just type
  :qq / :exit
in the debug dialog (or REPL).

Optionally you can also directly abort (see respective C function) by typing:

  :qa / :abort

On simple read errors on the REPL (e.g. non-existing packages, non-external symbols), the debugger will not be entered (as this would cause an unrecoverable break, since read runs in its own thread here); instead, the erroneous input string will be returned as-is.


The conflicting case

  (RESTART-TOPLEVEL)
  (RESTART-QT-EVENTS)
is resolved automatically (RESTART-QT-EVENTS would block the REPL in this case).
 
 

Tips

You might want to put this in your ~/.eclrc file:

  #+eql
  (setf eql:*qtpl*            t  ; same as -qtpl
        eql:*break-on-errors* t)
    


For running ECL / EQL through gdb (debugger), put this in your ~/.gdbinit file:

  handle SIGPWR nostop noprint
  handle SIGXCPU nostop noprint
    

You may find

  (qproperties object &optional (depth 1))

very convenient for debugging, as it prints the current state of the interesting object.


In order to automatically switch the REPL to a given package after loading a file, add this line:

  (qlater (lambda () (in-package :my-package)))

If you use ECL readline (see ~/.eql5/lib/ecl-readline.lisp, to be compiled manually after running EQL5 for the first time / updating ECL):
After entering :qq (quitting the top-level), the console/shell should always be reset (but you won't probably see the command while typing it; an alias might help):

  $ reset